package com.demo.task.service

import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.os.IBinder
import android.util.Log
import androidx.lifecycle.lifecycleScope
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider
import com.alibaba.sdk.android.oss.model.PutObjectRequest
import com.demo.task.bean.FilesInfo
import com.demo.task.bean.PlanBean
import com.demo.task.config.AliConfig.BUCKET_NAME
import com.demo.task.config.AliConfig.OSS_ACCESS_KEY_ID
import com.demo.task.config.AliConfig.OSS_ACCESS_KEY_SECRET
import com.demo.task.config.AliConfig.OSS_CALLBACK_URL
import com.demo.task.config.AliConfig.OSS_ENDPOINT
import com.demo.task.config.Config
import com.demo.task.config.ConfigUtils
import com.demo.task.config.PacketData.CLOSE_SCREEN
import com.demo.task.config.PacketData.SHOW_SCREEN
import com.demo.task.config.PacketData.VERSION_PACKET
import com.demo.task.config.PacketData.packetHeader
import com.demo.task.config.PacketData.screenPacket
import com.demo.task.download.DownloadManager
import com.demo.task.download.addDownloadListener
import com.demo.task.ext.MsgType
import com.demo.task.ext.getApkVersion
import com.demo.task.ext.getExternalFilesDir
import com.demo.task.ext.getScreenSize
import com.demo.task.ext.getUrlFileName
import com.demo.task.ext.getVersion
import com.demo.task.ext.isWithinDateRange
import com.demo.task.ext.isWithinTimeRange
import com.demo.task.ext.jsonFromUrl
import com.demo.task.ext.launchIO
import com.demo.task.ext.screenshot
import com.demo.task.ext.sendError
import com.demo.task.ext.toJson
import com.demo.task.manager.UsbSerialPortManager
import com.demo.task.remote.ApiService
import com.demo.task.socket.RemoteInterface
import com.demo.task.socket.UdpSocket
import com.example.rwxian.ZNlauncher.USBSerial.util.UsbUtils.sendBrightness
import com.orhanobut.logger.Logger
import com.simple.device.ApkUtils
import com.zed.service.APIHelper
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import javax.inject.Inject


@AndroidEntryPoint
class ConfigService : BaseService() {

    @Inject
    lateinit var socketIO: RemoteInterface

    @Inject
    lateinit var apiService: ApiService

    private val baseUdpSocket by lazy { UdpSocket(CLIENT_IP, CLIENT_PORT, 5000) }
    private val apiHelper by lazy { APIHelper.getInstance() }
    private val downloadManager by lazy {
        DownloadManager.Builder().savePath(getExternalFilesDir()).build()
    }

    private var controlJOb: Job? = null

    private val _updating = MutableSharedFlow<String>()
    val updating: SharedFlow<String> = _updating

    private var isNow = false

    override fun onCreate() {
        super.onCreate()
        Log.i(TAG, "onCreate: ")
        apiHelper.showNavBarAndStatusBar(false)
        baseUdpSocket.netInterface = "eth0"
        baseUdpSocket.connect(this)
        socketListener()
        initDataPack()
    }

    private fun initDataPack() {
        lifecycleScope.launch {
            UsbSerialPortManager.openDevice {
//                val usbPacket = usbPacket()
//                val packet1 = usbPacket[0]
//                val packet2 = usbPacket[1]
//                for (i in 0 until 10) {
//                    UsbSerialPortManager.write(packet1)
//                    delay(500)
//                    if (UsbSerialPortManager.writeData(packet2) != null) break
//                    delay(30_000)
//                }
            }
        }
    }

    private fun socketListener() {
        lifecycleScope.launch {
            socketIO.msg.collectLatest { msg ->
                val jsonObject = runCatching {
                    JSONObject(msg)
                }.getOrNull() ?: return@collectLatest

                jsonObject.optInt("sync").takeIf { it == 1 }?.also {
                    val packet = VERSION_PACKET.split(Regex("\\s+")) // 按一个或多个空白字符切分
                        .filter { it.isNotEmpty() }
                        .map { it.trim().toInt(16).toByte() }
                        .toByteArray()
                    val bytes = UsbSerialPortManager.writeData(packet)
                    val params = mapOf(
                        "sendcardv" to bytes.toString(),
                        "softv" to getVersion()
                    )
                    socketIO.sendBasic(params)
                }
                jsonObject.optInt("reboot").takeIf { it == 1 }?.also {
                    APIHelper.getInstance().rebootSys()
                }
                jsonObject.optInt("screenshot").takeIf { it == 1 }?.also {
                    uploadScreenshot()
                }
                jsonObject.optInt("getfile").takeIf { it == 1 }?.also {
                    launchIO {
                        uploadFileInfos()
                    }
                }
                jsonObject.optString("screen").takeIf { it.isNotEmpty() }?.also { data ->
                    val packet = data.split(Regex("\\s+")) // 按一个或多个空白字符切分
                        .filter { it.isNotEmpty() }
                        .map { it.trim().toInt(16).toByte() }
                        .toByteArray()
                    UsbSerialPortManager.write(packet)
                }
                jsonObject.optString("time").takeIf { it.isNotEmpty() }?.also {
                    if (!Config.isOpenGps) {
                        updateSysDate(it)
                    }
                    ConfigUtils.time = it
                }
                jsonObject.optString("closescreen").takeIf { it.isNotEmpty() }?.also {
                    val packet = CLOSE_SCREEN.split(Regex("\\s+")) // 按一个或多个空白字符切分
                        .filter { it.isNotEmpty() }
                        .map { it.trim().toInt(16).toByte() }
                        .toByteArray()
                    UsbSerialPortManager.write(packet)
                }
                jsonObject.optString("showscreen").takeIf { it.isNotEmpty() }?.also {
                    val packet = SHOW_SCREEN.split(Regex("\\s+")) // 按一个或多个空白字符切分
                        .filter { it.isNotEmpty() }
                        .map { it.trim().toInt(16).toByte() }
                        .toByteArray()
                    UsbSerialPortManager.write(packet)
                }
                jsonObject.optString("shutdown").takeIf { it.isNotEmpty() }?.also {
                    //APIHelper.getInstance().shutdownSys()
                }
                jsonObject.optString("closeinter").takeIf { it.isNotEmpty() }?.also {
                    //setAirPlaneMode(true)
                }
                jsonObject.optString("sendcardupdate").takeIf { it.isNotEmpty() }?.also { url ->
                    val json = withContext(Dispatchers.IO) {
                        url.jsonFromUrl()
                    }
                    val jsonArray =
                        runCatching { JSONArray(json) }.getOrDefault(JSONArray("[]"))
                    for (i in 0 until jsonArray.length()) {
                        val packet = jsonArray.getString(i).split(Regex("\\s+")) // 按一个或多个空白字符切分
                            .filter { it.isNotEmpty() }
                            .map { it.trim().toInt(16).toByte() }
                            .toByteArray()
                        UsbSerialPortManager.write(packet)
                        delay(100)
                    }
                }
            }
        }
    }

    /**
     * 上传文件信息
     */
    private fun uploadFileInfos() {
        val files = mutableListOf<FilesInfo>()
        File(getExternalFilesDir()).listFiles()?.forEach { file ->
            if (file.isDirectory) {
                file.listFiles()?.forEach { childFile ->
                    files.add(FilesInfo(childFile.path, childFile.length()))
                }
            } else {
                files.add(FilesInfo(file.path, file.length()))
            }
        }
        socketIO.send(mapOf("files" to files).toJson())
        Log.w(TAG, "getfile ${Thread.currentThread().name}: $files")
    }

    /**
     * 上传截图
     */
    private fun uploadScreenshot() {
        lifecycleScope.launchIO {
            val screenshot = screenshot()
            val objectKey = "jietu/${screenshot.name}"
            val provider = OSSPlainTextAKSKCredentialProvider(
                OSS_ACCESS_KEY_ID,
                OSS_ACCESS_KEY_SECRET
            )
            val oss = OSSClient(applicationContext, OSS_ENDPOINT, provider).apply {
                setRegion(OSS_CALLBACK_URL)
            }
            val put = PutObjectRequest(BUCKET_NAME, objectKey, screenshot.path)

            runCatching {
                oss.putObject(put)
                val downloadUrl = "https://${BUCKET_NAME}.${OSS_ENDPOINT}/$objectKey"
                Log.d(TAG, "screenshot: $downloadUrl ")
                socketIO.send(mapOf("screenshot" to downloadUrl).toJson())
                apiService.uploadScreen(downloadUrl)
            }.onFailure {
                it.printStackTrace()
            }
        }
    }


    private fun loadConfig(planBean: PlanBean) {
        // 设置系统宽高
        val screenSize = getScreenSize()
        Log.e(TAG, "screenSize: ${screenSize.first} ${screenSize.second}")
        if (planBean.pixelsW * screenSize.first != planBean.pixelsH * screenSize.second) {
            //APIHelper.getInstance().setSysDisplaySize(planBean.pixelsW, planBean.pixelsH)
        }

        if (planBean.isPixels == 1) {
            val screenPacket = screenPacket(
                planBean.inId,
                planBean.inNum,
                planBean.pixelsW,
                planBean.pixelsH
            )
            baseUdpSocket.send(screenPacket.packetHeader())
        }
        if (planBean.softUpdate == 1 && planBean.upgrade != null) {
            updateApk(planBean)
        }
        isNow = planBean.isNow == 1
        if (isNow) {
            baseUdpSocket.send(sendBrightness(planBean.brightness))
            lifecycleScope.launch { UsbSerialPortManager.write(sendBrightness(planBean.brightness)) }
        }
        loopControl(planBean)
    }

    private fun updateApk(planBean: PlanBean) {
        val upgrade = planBean.upgrade!!
        val apkUrl = upgrade.url
        if (apkUrl.isNotEmpty()) {
            downloadManager.download(apkUrl)
            downloadManager.addDownloadListener(
                prog = {
                    Log.w(TAG, "updateApk: $it")
                    runBlocking { _updating.emit("Updating：$it%") }
                },
                fileComplete = {
                    if (apkUrl == it) {
                        val apkFile = File(downloadManager.savePath, apkUrl.getUrlFileName())
                        val apkPath = apkFile.absolutePath
                        if (apkPath.getApkVersion(this@ConfigService) > getVersion()) {
                            Log.i(TAG, "getApkVersion: $apkPath")
                            Logger.i("getApkVersion: $apkPath")
                            runBlocking {
                                ConfigUtils.control = ConfigUtils.control?.apply {
                                    this.upgrade = null
                                }
                                delay(500)
                                _updating.emit("")
                            }
                            ApkUtils().installApk(apkPath)
                        } else {
                            runBlocking {
                                _updating.emit("Update failed: version too low")
                                delay(3_000)
                                _updating.emit("")
                            }
                        }
                    }
                }, failure = { url, t ->
                    Log.e(TAG, "updateApk: $url", t)
                    runBlocking {
                        socketIO.sendError(MsgType.DOWNLOAD.name, url, t.message)
                        _updating.emit("Update failed：${t.message}")
                        delay(3_000)
                        _updating.emit("")
                    }
                })
        }
    }

    private fun loopControl(planBean: PlanBean) {
        controlJOb?.cancel()
        controlJOb = lifecycleScope.launch {
            for (control in planBean.planControl ?: emptyList()) {
                while (true) {
                    if (isWithinDateRange(control.startDate, control.endDate) &&
                        isWithinTimeRange(control.startTime, control.endTime)
                    ) {
                        Config.controlId = control.id.toString()
                        setControl(control)
                        break
                    }
                    delay(1_000)
                }
            }
        }
    }

    private fun setControl(control: PlanBean.PlanControl) {
        // 配置系统声音
        control.vol?.let {
            APIHelper.getInstance()
                .setStreamVolume(AudioManager.STREAM_MUSIC, it, 0)
            APIHelper.getInstance()
                .setStreamVolume(AudioManager.STREAM_SYSTEM, it, 0)
        }
        control.ctr?.let {
            when (it) {
                1 -> APIHelper.getInstance().wakeUp() //亮屏
                2 -> APIHelper.getInstance().sleep() //息屏
                //3 -> APIHelper.getInstance().rebootSys() //重启
                //4 -> { }//开机无法控制
                //5 -> APIHelper.getInstance().shutdownSys() //关机

            }
        }
        if (!isNow && control.bns != null) {
            baseUdpSocket.send(sendBrightness(control.bns))
            lifecycleScope.launch { UsbSerialPortManager.write(sendBrightness(control.bns)) }
        }
        control.tem?.let { } //温度预警，预留
        control.dam?.let { } //湿度预警，预留
    }

    private fun updateSysDate(serverTime: String?) {
        if (!serverTime.isNullOrEmpty()) {
            val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            val dateTime = LocalDateTime.parse(serverTime, formatter)
            val year: Int = dateTime.year
            val month: Int = dateTime.monthValue
            val day: Int = dateTime.dayOfMonth
            val hour: Int = dateTime.hour
            val minute: Int = dateTime.minute
            val second: Int = dateTime.second
            apiHelper.setSysTime(year, month, day, hour, minute, second)
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.i(TAG, "onStartCommand: ")
        intent?.getParcelableExtra<PlanBean>("data")?.also {
            loadConfig(it)
        }
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent): IBinder {
        Log.i(TAG, "onBind: ")
        return super.onBind(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
        baseUdpSocket.close()
    }

    companion object {
        private const val TAG = "ConfigService"
        private const val CLIENT_PORT = 8080
        private const val CLIENT_IP = "192.168.4.2"

        fun Context.startConfigService(planBean: PlanBean) {
            val intent = Intent(this, ConfigService::class.java)
            intent.putExtra("data", planBean)
            startService(intent)
        }
    }
}
